function s = join (u, v)

   ## usage:  s = join (u, v)
   ##
   ## join two structures

   if isempty(u)
      s = v ;
      return ;
   endif
   if isempty(v)
      s = u ;
      return ;
   endif
   ## if all(isnan(u.x)(:))
   ##    s.id = v.id ; s.x = [nan(rows(v.x), columns(u.x)) v.x] ;
   ##    return ;
   ## endif
   ## if all(isnan(v.x)(:))
   ##    s.id = u.id ; s.x = [u.x nan(rows(u.x), columns(v.x))] ;
   ##    return ;
   ## endif

   Ju = datenum(u.id) ;
   Jv = datenum(v.id) ;
   IJu = !isnan(Ju) ; IJv = !isnan(Jv) ;
   Ju = Ju(IJu) ; Jv = Jv(IJv) ;

   ## I = fill_jul(Ju, Jv) ;
   I = unique([Ju ; Jv]) ; d = min(diff(I)) ;

   s.id = datevec(I)(:,1:columns(u.id)) ;

   Lu = findL(I, d, Ju, u.id) ;
   Lv = findL(I, d, Jv, v.id) ;

   fu = fieldnames(u) ; fv = fieldnames(v) ;
   for key=union(fu, fv)'

      key = key{:} ;

      switch key
	 case {"x", "z", "a"}
	    u.(key) = u.(key)(IJu,:) ; v.(key) = v.(key)(IJv,:) ; 
	    s.(key) = nan(rows(s.id), columns(u.(key))+columns(v.(key))) ;
	    s.(key)(Lu,1:columns(u.(key))) = u.(key) ;
	    s.(key)(Lv,columns(u.(key))+(1:columns(v.(key)))) = v.(key) ;
	 case {"cal"}
	    if (isfield(u, key))
	       s.(key) = u.(key) ;
	    else
	       s.(key) = v.(key) ;
	    endif 
	 case {"id"}
	    continue
	 otherwise
	    if !isfield(u, key), s.(key) = v.(key) ; endif
	    if !isfield(v, key), s.(key) = u.(key) ; endif
	    if isfield(u, key) && isfield(v, key), s.(key) = [u.(key) v.(key)] ; endif
      endswitch

   endfor

endfunction


function L = findL (I, d, J, id)

   ## usage: L = findL (I, d, J, id)
   ## 
   ## find J index in I

   f = dbstack ;

   n = length(I) ; ierr = 0 ;

   i = 1 ; L = nan(rows(J),1) ;
   for j=1:rows(J)

      for ii = i:n
	  if Li = (abs(I(ii) - J(j)) <= d/10)
	     break
	  endif
      endfor
      i = ii ;

      if !Li
	 disp(id(max(1,j-5):min(n,j+5),:)) ;
	 error("%s: found incorrect date.", f(1).name) ;
      else
	 L(j) = i ;
      endif

   endfor

endfunction
